﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace UDPHelper
{
    /// <summary>
    /// 协助管理UDP事件
    /// </summary>
    public class UDPManager
    {
        public UDPManager()
        {
            UDPPackageManager = new UDPPackageManager();
        }

        /// <summary>
        /// 使用的端口号
        /// </summary>
        public int Port { get; set; }

        private UDPPackageManager _UDPPackageManager = null;

        /// <summary>
        /// 消息管理类
        /// </summary>
        public UDPPackageManager UDPPackageManager
        {
            get { return _UDPPackageManager; }
            set
            {
                _UDPPackageManager = value;
                _UDPPackageManager.AddPushCallback(() => { ResetEvent.Set(); });
            }
        }

        private UdpClient _UdpClient = null;

        private List<Action<UDPPackage>> _ReceiveCallbackList = new List<Action<UDPPackage>>();

        /// <summary>
        /// 添加接收的回调
        /// </summary>
        /// <param name="func"></param>
        public void AddReceiveCallback(Action<UDPPackage> func)
        {
            _ReceiveCallbackList.Add(func);
        }

        /// <summary>
        /// 删除接收的回调
        /// </summary>
        /// <param name="func"></param>
        public void RemoveReceiveCallback(Action<UDPPackage> func)
        {
            _ReceiveCallbackList.Remove(func);
        }

        public void Start()
        {
            _is_runing = true;
            StartReceive();
            StartSend();
        }

        /// <summary>
        /// 重启事件
        /// </summary>
        private ManualResetEvent ResetEvent = new ManualResetEvent(false);

        /// <summary>
        /// 开始发送数据
        /// </summary>
        private void StartSend()
        {
            new Thread(() =>
            {
                while (IsRuning)
                {
                    if (UDPPackageManager.PopUDPPackageFromStack(out UDPBasePackage package))
                    {
                        SendUDPPackage(package);
                    }
                    else
                    {
                        ResetEvent.Reset();
                        ResetEvent.WaitOne(1000);
                    }
                }
            })
            {
                IsBackground = true
            }.Start();
        }

        /// <summary>
        /// 发送UDP数据包
        /// </summary>
        /// <param name="package"></param>
        private void SendUDPPackage(UDPBasePackage package)
        {
            if (_UdpClient == null)
                return;

            //var bytes = UDPPackageHelper.GetBytes(package);
            var bytes = package.Data ?? new byte[0];
            _UdpClient.Send(bytes, bytes.Length, new IPEndPoint(package.IPAddress, package.Port));
        }

        /// <summary>
        /// 开始接收数据
        /// </summary>
        private void StartReceive()
        {
            IPEndPoint point = new IPEndPoint(IPAddress.Any, Port);
            _UdpClient = new UdpClient(point);
            new Thread(() =>
            {
                while (IsRuning)
                {
                    lock (this)
                    {
                        var status = _UdpClient.BeginReceive(new AsyncCallback(ReceiveCallback), _UdpClient);
                        status.AsyncWaitHandle.WaitOne();
                    }
                }
            })
            {
                IsBackground = true
            }.Start();
        }

        /// <summary>
        /// 接收消息的回调
        /// </summary>
        /// <param name="iar"></param>
        private void ReceiveCallback(IAsyncResult iar)
        {
            // 这句话得加上不然可能会造成不稳定的BUG
            if (!iar.IsCompleted)
                return;

            UdpClient client = iar.AsyncState as UdpClient;

            if (client == null)
                return;

            try
            {
                IPEndPoint remote_point = new IPEndPoint(IPAddress.Any, 0);
                Byte[] bytes = client.EndReceive(iar, ref remote_point);

                var package = UDPPackageHelper.GetPackage(bytes, remote_point);

                UDPRequestContext.Current = new UDPRequestContext
                {
                    UDPData = bytes,
                    RemoteIP = remote_point,
                };

                var list = new List<Action<UDPPackage>>(_ReceiveCallbackList);
                foreach (var func in list)
                {
                    func(package);
                }
            }
            catch (Exception ex)
            {

            }
        }

        /// <summary>
        /// 停止运行
        /// </summary>
        public void Stop()
        {
            _is_runing = false;
        }

        private bool _is_runing = false;

        /// <summary>
        /// 是否正在运行
        /// </summary>
        public bool IsRuning
        {
            get { return _is_runing; }
        }
    }
}
